/*
 如何创建一个类组件？
   + 基于ES6中的 class 创建一个类 
   + 但是“必须”继承 react 中的 Component或者PureComponent 类
   + 而且“必须”在子类的原型对象上设置 render 函数，让其返回“需要构建的视图（virtualDOM）”

 为啥要继承？「DemoTwo子类、Component父类」
   + 让子类的实例，具有子类提供的私有属性，及子类原型上的公共方法
   + 最主要的是，还需让子类的实例，继承父类提供的私有属性，以及父类原型上的公共方法
    function Component(props, context, updater) {
        this.props = props;
        this.context = context;
        this.refs = emptyObject;
        this.updater = updater || ReactNoopUpdateQueue;
    }
    // 证明其是否为React类组件
    Component.prototype.isReactComponent={}
    // 修改状态且通知视图更新
    Component.prototype.setState=function (partialState,callback) {...}
    // 强制更新视图
    Component.prototype.forceUpdate=function (callback) {...}

 当基于 render 方法渲染类组件的时候，会基于 new 创造类组件的一个实例，此时在React内部，会历经一系列的处理步骤「也就是从 new 开始，到视图渲染完毕，会经历很多事情 --> 组件第一次渲染的逻辑」
   @1 初始化 props && context
     + 接收传递的属性
     + 并且对属性进行规则校验 defaultProps/propTypes「静态私有属性」

   @2 执行 constructor 函数「前提是设置了这个函数」，把处理好的 props/context 传递进去
     constructor(props, context) {
        super(props, context)
        //如果设置了 constructor，在 extends 继承中，一定要加上 super「类似于call继承」
        //而且建议把 props 传递进去，这样此时就给 实例对象「this」 设置props属性 
     }

   @3 各种信息的初始化处理「或者说，把各种数据全部挂载到实例上」
     + 属性：this.props 
     + 上下文：this.context
     + REF操作：this.refs
     + 更新队列：this.updater
     + 状态：this.state 「如果我们没有手动去初始化状态，则其默认值是 null；状态在组件中是很重要的，是我们在组件内自己构建的数据模型（Model层），我们可以按照需求随意更改状态数据，并且控制视图的渲染和更新」
   
   @4 触发 componentWillMount 钩子函数「生命周期函数」执行
     组件第一次渲染之前
     特点：
       + 这个钩子函数此时是不安全的（未来可能要被移除了），所以官方不建议我们使用
       + 如果继续使用，在控制台会有黄色警告！
       + 如果不想出现警告错误，需要把其前面加上 UNSAFE_
       + 但是一旦设置了这个前缀，再 <React.StrictMode> 模式下，控制台会报错

    @5 触发 render 钩子函数执行
      render函数就是类组件中用来构建视图的函数「返回virtualDOM」
      此函数中的 this 就是当前类的实例

    @6 触发 componentDidMount 钩子函数执行
      组件第一次渲染完毕
      特点：
        + 此时我们可以获取到真实的DOM了
        + 真实项目中，我们一般会在此处
          + 发送数据请求，获取真实的数据
          + 设置定时器或者监听器，完成一些需求
          + ...
 */

import { Component } from 'react'
import PT from 'prop-types'

class DemoTwo extends Component {
    /* 属性规则校验 */
    static defaultProps = {
        x: 0,
        y: false
    }
    static propTypes = {
        title: PT.string.isRequired,
        x: PT.oneOfType([PT.number, PT.string]),
        y: PT.bool
    }

    /* 初始化状态 */
    state = {
        num: this.props.x
    }

    UNSAFE_componentWillMount() {
        console.log('第一次渲染之前')
    }

    componentDidMount() {
        console.log('第一次渲染完毕')
    }

    render() {
        console.log(this)
        return <div className="box">
            哈哈哈
        </div>
    }
}

export default DemoTwo


